/**
  ******************************************************************************
  * @file   :   main.c
  * @version:
  * @author :
  * @brief  :
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright(c) . BLUEX Microelectronics.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */

/* includes ------------------------------------------------------------------*/

#include "bx_kernel.h"
#include "user_app.h"

#include <easyflash.h>
#include "bx_shell.h"
#include "bxsh_uart.h"
#include "bx_service_uart.h"
#include "bx_service_tim.h"
#include "user_service_module_driver.h"
#include "user_service_module_InitiateConnection.h"
#include "user_service_module_SetPassthrough.h"
#include "user_service_module_reboot.h"
#include "user_service_module_QueryMac.h"
#include "user_service_module_SetMaster.h"
#include "user_service_module_SendDataReq.h"
#include "user_service_module_InitiateDisconnect.h"
#include "user_service_module_DeleteMacCorrelation.h"
#include "user_service_module_ReceiveThenResponse.h"
#include "bx_fifo.h"
#include "bx_service_uart.h"
#include "uart_cmd_def.h"
#include "log.h"

#define TEST_PERF 0

#if TEST_PERF
#include "bx_drv_gpio.h"
#include "bx_service_gpio.h"
#define TEST_IO_PIN 2
#endif

extern s32 user_service_id;
/* private define ------------------------------------------------------------*/
#define UART_BUF_SIZE 64

#define MAX_ONESHOT_DATA_LEN 32
#define MAX_ACC_DATA_LEN 32*8
#define MAX_ACC_RSP_LEN 32*8
/* private typedef -----------------------------------------------------------*/

/* private variables ---------------------------------------------------------*/
u8 uart_rx_buffer[UART_BUF_SIZE];
u8 uart_tx_buffer[UART_BUF_SIZE];

static enum bx_module_command_ids module_current_cmd_id;

/* exported variables --------------------------------------------------------*/

/*============================= private function =============================*/

/*========================= end of private function ==========================*/


/*============================= exported function ============================*/
void set_cmd_id(enum bx_module_command_ids cid)
{
    module_current_cmd_id = cid;
}

//u32 get_cmd_id(void)
//{
//    return module_current_cmd_id;
//}

bool check_cmd_id(enum bx_module_command_ids cid)
{
    return (module_current_cmd_id == cid);
}

void uart0_recv_start(void);

/** ---------------------------------------------------------------------------
 * @brief   :
 * @note    :
 * @param   :
 * @retval  :
-----------------------------------------------------------------------------*/
void user_init( void )
{
#if TEST_PERF
    bxs_gpio_register();
#endif
    bxsh_uart_init();
    bxs_uart_register();
    bxs_tim_register();
    us_module_driver_register();
    us_module_reboot_register();
    us_QueryMac_register();
#if ROLE_MASTER
    us_SetMaster_register();
    us_module_InitiateConnection_register();
    us_module_SetPassthrough_register();
    us_SendDataReq_register();
    us_InitiateDisconnect_register();
    us_DeleteMacCorrelation_register();
#else
    /* slaver */
    us_ReceiveThenResponse_register();
#endif
}

/** ---------------------------------------------------------------------------
 * @brief   :
 * @note    :
 * @param   :
 * @retval  :
-----------------------------------------------------------------------------*/
void user_app( void )
{
#if TEST_PERF
    bx_call( bxs_gpio_a_id(), BXM_OPEN, 0, 0 );
    bx_set( bxs_gpio_a_id(), BXP_MODE, 2, BX_GPIO_MODE_OUTPUT );
    bx_drv_gpio_write ( BX_GPIOA, TEST_IO_PIN, 0 );
#endif
    bx_set ( bxs_uart0_id(), BXP_UART_RXBUFF, (u32)uart_rx_buffer, UART_BUF_SIZE);
    bx_set ( bxs_uart0_id(), BXP_UART_TXBUFF, (u32)uart_tx_buffer, UART_BUF_SIZE);

//subscribe start
    bx_subscibe( bxs_tim0_id(), BXM_TIM0_INTR, 0, 0 );
    bx_subscibeex( us_module_driver_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);

    bx_subscibeex( us_module_reboot_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_module_reboot_id(),  user_service_id, BXM_USER_CMD_RSP_READY);

    bx_subscibeex( us_QueryMac_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_QueryMac_id(),  user_service_id, BXM_USER_CMD_RSP_READY);

#if ROLE_MASTER
    bx_subscibeex( us_SetMaster_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_SetMaster_id(),  user_service_id, BXM_USER_CMD_RSP_READY);

    bx_subscibeex( us_module_InitiateConnection_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_module_InitiateConnection_id(),  user_service_id, BXM_USER_CMD_RSP_READY);
//  bx_subscibeex( us_module_InitiateConnection_id(),  user_service_id, BXM_USER_DATA_READY);

    bx_subscibeex( us_module_SetPassthrough_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_module_SetPassthrough_id(),  user_service_id, BXM_USER_CMD_RSP_READY);
//  bx_subscibeex( us_module_SetPassthrough_id(),  user_service_id, BXM_USER_DATA_READY);

    bx_subscibeex( us_SendDataReq_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_SendDataReq_id(),  user_service_id, BXM_USER_DATA_READY);

    bx_subscibeex( us_InitiateDisconnect_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_InitiateDisconnect_id(),  user_service_id, BXM_USER_CMD_RSP_READY);

    bx_subscibeex( us_DeleteMacCorrelation_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_DeleteMacCorrelation_id(),  user_service_id, BXM_USER_CMD_RSP_READY);
#else
    /* slaver */
    bx_subscibeex( us_ReceiveThenResponse_id(),  user_service_id, BXM_USER_TIMER_TIMEOUT);
    bx_subscibeex( us_ReceiveThenResponse_id(),  user_service_id, BXM_USER_DATA_READY);
#endif
//subscribe end

    bx_call( bxs_tim0_id(), BXM_OPEN, 0, 0 );
    bx_call( bxs_tim0_id(), BXM_START, 1000, 0 );

    bx_post( us_module_driver_id(), USM_MODULE_DRIVER_START ,0 ,0);

    struct bx_uart_service * p_uart0_svc;
    p_uart0_svc = get_uart0_svc();
    bx_fifo_clear(&( p_uart0_svc->rx_fifo ));
    uart0_recv_start();
}

static u32 soft_timer_counter = 0;
static u32 soft_timer_cmp = 0;

bx_err_t user_module_msg_handle_func( u32 src_id, u32 msg, u32 param0, u32 param1 )
{
    switch( msg ) {

        case BXM_USER_TIMER_START:
            //LOG_RAW("@ user app start timer, src id: %d, p0: 0x%x, p1: 0x%x \n",src_id, param0, param1);
            soft_timer_counter = 0;
            soft_timer_cmp = param0;
            break;

        case BXM_USER_TIMER_STOP:
            soft_timer_cmp = 0;
            break;
        default:
            break;
    }
    return BX_OK;
}

static u8 dat_pub_buf[MAX_ACC_DATA_LEN];
static u32 dat_pub_cur_idx;
static u8 rsp_pub_buf[MAX_ACC_RSP_LEN];
static u32 rsp_pub_cur_idx;

static __inline void uart0_recv_buff(void)
{
    static u8 dat_ready_buf[MAX_ONESHOT_DATA_LEN];
    static u8 content_length;
    static u8 content_count;
    struct bx_uart_service * p_uart0_svc;

    p_uart0_svc = get_uart0_svc();
    u32 ready_len = bx_fifo_get_len( &( p_uart0_svc->rx_fifo ) );

    if ( ready_len )
    {
        bx_fifo_fast_pop( &( p_uart0_svc->rx_fifo ), dat_ready_buf, ready_len );

        u32 i = 0;
        u32 cmd_step = HEAD_F;

        for ( u32 loop_len = ready_len; loop_len > 0; --loop_len )
        {
            switch ( cmd_step )
            {
                case HEAD_F:
                {
                    if ( 0xAA == dat_ready_buf[i] )
                    {
                        cmd_step = HEAD_B;
                        ++i;
                    }else
                    {
                        cmd_step = NOT_CMD;
                    }
                }
                break;

                case HEAD_B:
                {
                    if ( 0x55 == dat_ready_buf[i] )
                    {
                        cmd_step = CMD_ID;
                        ++i;
                    }else
                    {
                        cmd_step = NOT_CMD;
                    }
                }
                break;

                case CMD_ID:
                {
                    if ( (( dat_ready_buf[i] >= UART_COMMAND_ENTER_TRANSPARENT_MODEL )&&( dat_ready_buf[i] <= UART_COMMAND_SET_UART_BPS )) ||
                         (( dat_ready_buf[i] >= UART_COMMAND_GET_DEVICE_CLASS )&&( dat_ready_buf[i] <= UART_COMMAND_SET_PASSWORD )) ||
                         (( dat_ready_buf[i] >= UART_COMMAND_START_SCAN )&&( dat_ready_buf[i] <= UART_COMMAND_GET_RSSI ))
                       )
                    {
                        cmd_step = CMD_LEN;
                        ++i;
                    }else
                    {
                        cmd_step = NOT_CMD;
                    }
                }
                break;

                case CMD_LEN:
                {
                    content_length = dat_ready_buf[i];
                    content_count = content_length - 1;
                    cmd_step = CMD_CONTENT;
                    ++i;
                }
                break;

                case CMD_CONTENT:
                {
                    if ( content_count ) {
                        --content_count;
                    }else{
                        cmd_step = CHECK_SUM;
                    }
                    ++i;
                }
                break;
                
                case CHECK_SUM:
                {
                    u8 check_sum = dat_ready_buf[i];
                    u32 calc_acc = 0;
                    
                    //accumulate to calc summary
                    u8 *p = &dat_ready_buf[2];
                    while( p < &dat_ready_buf[i] )
                    {
                        calc_acc += *p++;
                    }
                    //chop to get result
                    u8 calc_sum = (u8)calc_acc;
                    
                    if ( check_sum == calc_sum ) {
                        cmd_step = CMD_END;
                    }else{
                        cmd_step = NOT_CMD;
                    }
                }
                break;
                
                case CMD_END:{}
                default:break;
            }

            if ( NOT_CMD == cmd_step )
            {
                dat_pub_cur_idx = 0;
                memcpy ( &dat_pub_buf[dat_pub_cur_idx], dat_ready_buf, ready_len );
                dat_pub_cur_idx = ready_len;
                
                bx_public( user_service_id, BXM_USER_DATA_READY, (u32)dat_pub_buf, dat_pub_cur_idx );
                break;
            }
            else if ( CMD_END == cmd_step )
            {
                memcpy ( &rsp_pub_buf[0], dat_ready_buf+2, i-2 );//skip head(0xAA,0x55), copy cmd+len+content only
                rsp_pub_cur_idx = i-2;
                
                bx_public( user_service_id, BXM_USER_CMD_RSP_READY, (u32)rsp_pub_buf, rsp_pub_cur_idx );
                break;
            }
        }
        
//        else{
//        //loop out, need merge next
//            ++merge_count;
//        }

    }
}

/** ---------------------------------------------------------------------------
 * @brief   :
 * @note    :
 * @param   :
 * @retval  :
-----------------------------------------------------------------------------*/

bx_err_t user_msg_handle_func(s32 svc, u32 msg,u32 param0,u32 param1 )
{
#if TEST_PERF
bx_drv_gpio_write ( BX_GPIOA, TEST_IO_PIN, 1 );
#endif
    s32 msg_src = bx_msg_source();
    if( msg_src == bxs_tim0_id() )
    {
        if ( msg != BXM_TIM0_INTR )
            return BX_OK;

        uart0_recv_buff();

        if ( 0 == soft_timer_cmp )
            return BX_OK;

        ++soft_timer_counter;
        if (soft_timer_counter == soft_timer_cmp)
        {
            bx_public( user_service_id, BXM_USER_TIMER_TIMEOUT, soft_timer_cmp, soft_timer_counter );
            soft_timer_cmp = 0;
        }
    }
    else
    {
        user_module_msg_handle_func( msg_src, msg, param0, param1 );
    }
#if TEST_PERF
bx_drv_gpio_write ( BX_GPIOA, TEST_IO_PIN, 0 );
#endif
    return BX_OK;
}
/*========================= end of exported function =========================*/


/*============================= import function ==============================*/

/*=========================== end of import function =========================*/


/*============================ interrupt function ============================*/

/*========================= end of interrupt function ========================*/

  
/******************** (C) COPYRIGHT BLUEX **********************END OF FILE****/



